package com.gitee.ywj1352.jdk8;

import javax.tools.*;
import java.io.File;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

/**
 * @author wenjie.yang on 2019/11/27.
 */
public class JavaCompilerDemo{

    public static void main(String[] args) {
        GetingFun eval = eval();
        String s = eval.fun("哈巴河");
        System.out.println(s);
    }

    private static WeakReference<JavaCompilerDemo> mWeakReference = new WeakReference<>(new JavaCompilerDemo());

    public static GetingFun eval() {
        JavaCompilerDemo eval = mWeakReference.get();

        String codes = "public String fun(String s){" +
                            "System.out.println(\"hello world\"); " +
                            "com.gitee.ywj1352.jdk8.ReferenceDemo r = new com.gitee.ywj1352.jdk8.ReferenceDemo();" +
                            "r.fun();"+
                            "return \"你好:\" + s;"+
                        "}";
        GetingFun instance = eval.getInstance(codes);
        return instance;
    }

    private GetingFun getInstance(String codes){

        String className = "com.gitee.ywj1352.jdk8.Eval";
        StringBuilder sb = new StringBuilder();
        sb.append("package com.gitee.ywj1352.jdk8;");
        sb.append("\n public class Eval implements com.gitee.ywj1352.jdk8.GetingFun{\n ");
        sb.append(codes);
        sb.append("\n}");

        Class<?> clazz = compile(className, sb.toString());
        try {
            // 生成对象
            Object obj = clazz.newInstance();
            // 调用sayHello方法
            return (GetingFun)obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public Class<?> compile(String className,String javaCodes){
        //1.获取 JavaCompiler 类
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        //2.获取 java file Manager
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null, null);

        //3.创建 javaObject 对象
        StrSrcJavaObject srcObject = new StrSrcJavaObject(className, javaCodes);
        Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(srcObject);
        String flag = "-d";
        String outDir = "";
        try {
            //指定 当前 目录
            File classPath = new File(Thread.currentThread().getContextClassLoader().getResource("").toURI());
            outDir = classPath.getAbsolutePath() + File.separator;
        } catch (URISyntaxException e1) {
            e1.printStackTrace();
        }
        Iterable<String> options = Arrays.asList(flag, outDir);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, fileObjects);
        boolean result = false;
        try{
            result = task.call();
        }catch (NoClassDefFoundError e){}
        if (result) {
            try {
                return Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;

    }

    private static class StrSrcJavaObject extends SimpleJavaFileObject {
        private String content;
        // 指定 com/gitee/ywj1352/jdk8/Eval.java uri
        StrSrcJavaObject(String name, String content) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.content = content;
        }
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return content;
        }
    }

}
